﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using System.Windows.Forms;

using FWF.Logging.Net;

namespace FWF.Logging.Viewer
{
    /// <summary>
    /// 
    /// </summary>
    public partial class frmMain : Form, ILoggerListener
    {
        private readonly List<LogEventItem> _items = new List<LogEventItem>();

        private static volatile object _lockObject = new object();

        #region Constructors / Finalier

        /// <summary>
        /// Initializes a new instance of the <see cref="frmMain"/> class.
        /// </summary>
        public frmMain()
        {
            InitializeComponent();
        }

        #endregion

        #region Form Events

        /// <summary>
        /// Handles the Load event of the frmMain control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void frmMain_Load( object sender, EventArgs e )
        {
            //
            Disconnect();

            // Register this component to receive all log events 
            ObserverAppender.AddHandler( this );

            //
            LogSubscriber.RegisterAndListen();

            // If application was opened from a file, then open that file
            string[] args = Environment.GetCommandLineArgs();

            if ( args.Length > 0 )
            {
                foreach ( string arg in args )
                {
                    if ( arg.ToLower().EndsWith( ".mflog" ) )
                    {
                        OpenPackage( arg );
                        break;
                    }
                }
            }
        }

        /// <summary>
        /// Handles the FormClosing event of the frmMain control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.FormClosingEventArgs"/> instance containing the event data.</param>
        private void frmMain_FormClosing( object sender, FormClosingEventArgs e )
        {
            LogSubscriber.Disconnect();
        }

        #endregion

        #region Toolbar Events

        /// <summary>
        /// Handles the Click event of the toolStripConnect control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void toolStripConnect_Click( object sender, EventArgs e )
        {
            Connect();
        }

        /// <summary>
        /// Handles the Click event of the openToolStripButton control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void openToolStripButton_Click( object sender, EventArgs e )
        {
            //
            DialogResult result = diaOpenFile.ShowDialog( this );

            //
            if ( result != DialogResult.OK && result != DialogResult.Yes )
            {
                return;
            }

            OpenPackage( diaOpenFile.FileName );
        }

        /// <summary>
        /// Handles the Click event of the saveToolStripButton control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void saveToolStripButton_Click( object sender, EventArgs e )
        {
            //
            diaSaveResults.FileName = "LogViewerResults." + DateTime.Now.ToString( "MM.dd.yyyy" );

            DialogResult result = diaSaveResults.ShowDialog( this );

            //
            if ( result != DialogResult.OK && result != DialogResult.Yes )
            {
                return;
            }

            SavePackage( diaSaveResults.FileName, true );
        }

        /// <summary>
        /// Handles the Click event of the copyToolStripButton control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void copyToolStripButton_Click( object sender, EventArgs e )
        {
            //Clipboard.SetText( ctrlMessageLog.GetCurrentCellValue() );
        }

        /// <summary>
        /// Handles the Click event of the helpToolStripButton control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void helpToolStripButton_Click( object sender, EventArgs e )
        {
            using ( frmAbout frm = new frmAbout() )
            {
                frm.ShowDialog( this );
            }
        }

        /// <summary>
        /// Handles the Click event of the filterToolStripButton control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void filterToolStripButton_Click( object sender, EventArgs e )
        {
            //ctrlMessageLog.EditFilters();
        }

        /// <summary>
        /// Handles the Click event of the newToolStripButon control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void newToolStripButon_Click( object sender, EventArgs e )
        {
            //ctrlMessageLog.Clear();
        }

        /// <summary>
        /// Handles the Click event of the exportToolStripButton control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void exportToolStripButton_Click( object sender, EventArgs e )
        {
            //// Do not export when there are no items displayed
            //if ( !ctrlMessageLog.Items.HasItems() )
            //{
            //    return;
            //}

            //DialogResult result;
            //string filePath = string.Empty;
            //ExportGranularity granularity;

            //using ( frmExport frm = new frmExport() )
            //{
            //    result = frm.ShowDialog( this );

            //    if ( result != DialogResult.OK && result != DialogResult.Yes )
            //    {
            //        return;
            //    }

            //    //
            //    filePath = frm.FilePath;
            //    granularity = frm.Granularity;
            //}

            ////
            //ExportPackage( filePath, granularity );
        }

        #endregion

        #region Drag and Drop

        /// <summary>
        /// Handles the DragDrop event of the frmMain control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.DragEventArgs"/> instance containing the event data.</param>
        private void frmMain_DragDrop( object sender, DragEventArgs e )
        {
            Array args = (Array)e.Data.GetData( DataFormats.FileDrop );

            if ( args != null && args.Length > 0 )
            {
                OpenPackage( args.GetValue( 0 ) as string );
            }
        }

        /// <summary>
        /// Handles the DragEnter event of the frmMain control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.DragEventArgs"/> instance containing the event data.</param>
        private void frmMain_DragEnter( object sender, DragEventArgs e )
        {
            if ( e.Data.GetDataPresent( DataFormats.FileDrop ) )
            {
                e.Effect = DragDropEffects.Copy;
            }
            else
            {
                e.Effect = DragDropEffects.None;
            }
        }

        /// <summary>
        /// Handles the DragDrop event of the gridMessages control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.DragEventArgs"/> instance containing the event data.</param>
        private void ctrlMessageLog_DragDrop( object sender, DragEventArgs e )
        {
            Array args = (Array)e.Data.GetData( DataFormats.FileDrop );

            if ( args != null && args.Length > 0 )
            {
                OpenPackage( args.GetValue( 0 ) as string );
            }
        }

        /// <summary>
        /// Handles the DragEnter event of the gridMessages control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.DragEventArgs"/> instance containing the event data.</param>
        private void ctrlMessageLog_DragEnter( object sender, DragEventArgs e )
        {
            if ( e.Data.GetDataPresent( DataFormats.FileDrop ) )
            {
                e.Effect = DragDropEffects.Copy;
            }
            else
            {
                e.Effect = DragDropEffects.None;
            }
        }

        #endregion

        #region ILoggerListener Members

        /// <summary>
        /// 
        /// </summary>
        /// <param name="logEventItem">The logging event item.</param>
        public void Log( LogEventItem logEventItem )
        {
            lock ( _lockObject )
            {
                _items.Add( logEventItem );
            }
        }

        #endregion

        /// <summary>
        /// Connects this instance.
        /// </summary>
        private void Connect()
        {
            DialogResult result;

            using ( var frm = new frmConnect() )
            {
                result = frm.ShowDialog( this );
            }

            if ( result != DialogResult.OK )
            {
                return;
            }

            // Reset
            _items.Clear();
            ctrlMessageLog.Clear();

            //
            toolStripConnect.Text = "Disconnect";

            //
            toolStripConnectedToLabel.Text = "Connected To:";
            toolStripConnectedToDetailLabel.Text = LogSubscriber.PublisherUrl.ToString();
        }

        /// <summary>
        /// Disconnects this instance.
        /// </summary>
        private void Disconnect()
        {
            //
            toolStripConnectedToLabel.Text = "Not Connected";
            toolStripConnectedToDetailLabel.Text = string.Empty;

            //
            toolStripConnect.Text = "Connect";

            //
            LogSubscriber.Disconnect();
        }

        /// <summary>
        /// Resets this instance.
        /// </summary>
        private void Reset()
        {
            _items.Clear();
            ctrlMessageLog.Clear();
        }

        /// <summary>
        /// Refreshes the log data.
        /// </summary>
        private void RefreshLogData()
        {
            lock ( _lockObject )
            {
                _items.ForEach(
                    x => ctrlMessageLog.LogMessage( x )
                    );

                _items.Clear();
            }
        }

        /// <summary>
        /// Saves the package.
        /// </summary>
        /// <param name="file">The file.</param>
        /// <param name="saveWithCompression">if set to <c>true</c> [save with compression].</param>
        private void SavePackage( string file, bool saveWithCompression )
        {
            try
            {
                Cursor = Cursors.WaitCursor;

                lock ( _lockObject )
                {
                    //LogEventPackage pkg = new LogEventPackage();
                    //pkg.Name = "Log Viewer Results";

                    //pkg.Description =
                    //    string.Format(
                    //    "Message Viewer Results from: {0}",
                    //    Program.ConnectionString
                    //    );

                    //// Add each row
                    //ctrlMessageLog.Items.ForEach(
                    //    x => pkg.AddItem( x )
                    //    );

                    ////
                    //pkg.Save( file, saveWithCompression );
                }
            }
            finally
            {
                this.Cursor = Cursors.Default;
            }
        }

        ///// <summary>
        ///// Exports the package.
        ///// </summary>
        ///// <param name="file">The file.</param>
        ///// <param name="granularity">The granularity.</param>
        //private void ExportPackage( string file, ExportGranularity granularity )
        //{
        //    //try
        //    //{
        //    //    this.Cursor = Cursors.WaitCursor;

        //    //    ExportLogPackage pkg = ExportLogPackage.Create( granularity );

        //    //    // Add each row
        //    //    ctrlMessageLog.Items.ForEach(
        //    //        x => pkg.AddItem( x )
        //    //        );

        //    //    pkg.Save( file );
        //    //}
        //    //finally
        //    //{
        //    //    this.Cursor = Cursors.Default;
        //    //}
        //}

        /// <summary>
        /// Opens the package.
        /// </summary>
        /// <param name="file">The file.</param>
        private void OpenPackage( string file )
        {
            try
            {
                Cursor = Cursors.WaitCursor;

                //
                Disconnect();

                //
                Reset();

                //if ( !Path.GetExtension( file ).EqualsIgnoreCase( ".fwflog" ) )
                //{
                //    return;
                //}
                if ( !File.Exists( file ) )
                {
                    MessageBox.Show( "Invalid file location: " + file );
                    return;
                }

                lock ( _lockObject )
                {
                    //
                    Program.FilePath = file;

                    LogEventPackage pkg = LogEventPackage.CreateFromFile( file );

                    //
                    foreach ( LogEventItem itm in pkg.Items )
                    {
                        _items.Add( itm );
                    }
                }
            }
            finally
            {
                Cursor = Cursors.Default;
            }
        }

        /// <summary>
        /// Handles the Tick event of the timerAutoRefresh control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        [DebuggerStepThrough]
        private void timerAutoRefresh_Tick( object sender, EventArgs e )
        {
            // Call Invoke to process refresh click on UI thread
            Invoke(
                new MethodInvoker( RefreshLogData )
                );
        }


        
    }
}
